标 志 寄存器 |
BIT31—BIT18 | BIT17 | BIT16 | BIT15 | BIT14 | BIT13—BIT12 | BIT11 | BIT10 | BIT9 | BIT8 | BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0 |
00000000000000 | V M |
R F |
0 | N T |
IOPL | OF | D F |
I F |
T F |
S F |
Z F |
0 | A F |
0 | P F |
1 | C F |
I/O敏感指令 | 指令 | 功能 | 保护方式下的执行条件 |
CLI | 清除EFLAGS中的IF位 | CPL<=IOPL | |
STI | 设置EFLAGS中的IF位 | CPL<=IOPL | |
IN | 从I/O地址读出数据 | CPL<=IOPL或I/O位图许可 | |
INS | 从I/O地址读出字符串 | CPL<=IOPL或I/O位图许可 | |
OUT | 向I/O地址写数据 | CPL<=IOPL或I/O位图许可 | |
OUTS | 向I/O地址写字符串 | CPL<=IOPL或I/O位图许可 |
TSSSEG SEGMENT PARA USE16 TSS <> ;TSS低端固定格式部分 DB 8 DUP(0) ;对应I/O端口00H—3FH DB 10000000B ;对应I/O端口40H—47H DB 01100000B ;对用I/O端口48H—4FH DB 8182 DUP(0ffH) ;对应I/O端口50H—0FFFFH DB 0FFH ;位图结束字节 TSSLen = $ TSSSEG ENDS
in al,21h ;(1)正常执行 in al,47h ;(2)引起异常 out 20h,al ;(3)正常实行 out 4eh,al ;(4)引起异常 in al,20h ;(5)正常执行 out 20h,eax ;(6)正常执行 out 4ch,ax ;(7)引起异常 in ax,46h ;(8)引起异常 in eax,42h ;(9)正常执行
不同特权级对 标志寄存器特 殊字段的处理 |
特权级 | VM标志字段 | IOPL标志字段 | IF标志字段 |
CPL=0 | 可变(初POPF指令外) | 可变 | 可变 | |
0不变 |
不变 |
可变 |
| |
CPL>IOPL | 不变 | 不变 | 不变 |
;名称:ASM9.ASM ;功能:演示I/O保护及I/O敏感指令的作用 ;编译:TASM ASM9.ASM ;连接:TLINK /32 ASM9.OBJ ;---------------------------------------------------------------------------- INCLUDE 386SCD.INC ;---------------------------------------------------------------------------- GDTSeg SEGMENT PARA USE16 ;全局描述符表段(16位) GDT LABEL BYTE ;空描述符 DUMMY Desc <> ;规范段描述符及选择子 Normal Desc <0ffffh,,,ATDW,,> Normal_Sel = Normal-GDT ;视频缓冲区段描述符(DPL=3)及选择子(任何特权级可写) VideoBuf Desc <07fffh,8000h,0bh,ATDW,,> VideoBuf_Sel = VideoBuf-GDT ;---------------------------------------------------------------------------- EFFGDT LABEL BYTE ;演示任务TSS段描述符及选择子 DemoTSS Desc <DemoTSSLen-1,DemoTSSSeg,,AT386TSS,,> DemoTSS_Sel = DemoTSS-GDT ;演示任务堆栈段描述符及选择子 DemoStack Desc <DemoStackLen-1,DemoStackSeg,,ATDW,D32,> DemoStack_Sel = DemoStack-GDT ;演示代码段描述符及选择子 DemoCode Desc <DemoCodeLen-1,DemoCodeSeg,,ATCE,D32,> DemoCode_Sel = DemoCode-GDT ;属于演示任务的临时代码段描述符及选择子 TempCode Desc <0ffffh,TempCodeSeg,,ATCE,,> TempCode_Sel = TempCode-GDT ;指向GDT的存储段描述符及选择子 ToGDT Desc <GDTLen-1,GDTSeg,,ATDW,,> ToGDT_Sel = ToGDT-GDT ;指向通用保护故障处理任务TSS的存储段描述符及选择子 ToGPTSS Desc <GPTSSLen-1,GPTSSSeg,,ATDW,,> ToGPTSS_Sel = ToGPTSS-GDT ;指向测试任务TSS的存储段描述符及选择子 ToTestTSS Desc <TestTSSLen-1,TestTSSSeg,,ATDW,,> ToTestTSS_Sel = ToTestTSS-GDT ;测试任务TSS段描述符及选择子 TestTSS Desc <TestTSSLen-1,TestTSSSeg,,AT386TSS,,> TestTSS_Sel = TestTSS-GDT ;测试任务1堆栈段描述符(DPL=1)及选择子 Test1Stack Desc <TestStackLen-1,TestStackSeg,,ATDW+DPL1,D32,> Test1Stack_Sel = Test1Stack-GDT+RPL1 ;测试任务1代码段描述符(DPL=1)及选择子 Test1Code Desc <TestCodeLen-1,TestCodeSeg,,ATCE+DPL1,D32,> Test1Code_Sel = Test1Code-GDT+RPL1 ;测试任务2堆栈段描述符(DPL=2)及选择子 Test2Stack Desc <TestStackLen-1,TestStackSeg,,ATDW+DPL2,D32,> Test2Stack_Sel = Test2Stack-GDT+RPL2 ;测试任务2代码段描述符(DPL=2)及选择子 Test2Code Desc <TestCodeLen-1,TestCodeSeg,,ATCE+DPL2,D32,> Test2Code_Sel = Test2Code-GDT+RPL2 ;测试任务3堆栈段描述符(DPL=3)及选择子 Test3Stack Desc <TestStackLen-1,TestStackSeg,,ATDW+DPL3,D32,> Test3Stack_Sel = Test3Stack-GDT+RPL3 ;测试任务3代码段描述符(DPL=3)及选择子 Test3Code Desc <TestCodeLen-1,TestCodeSeg,,ATCE+DPL3,D32,> Test3Code_Sel = Test3Code-GDT+RPL3 ;通用保护故障处理任务的TSS段描述符及选择子 GPTSS Desc <GPTSSLen-1,GPTSSSeg,,AT386TSS,,> GPTSS_Sel = GPTSS-GDT ;通用保护故障处理任务的堆栈段描述符及选择子 GPStack Desc <GPStackLen-1,GPStackSeg,,ATDW,D32,> GPStack_Sel = GPStack-GDT ;通用保护故障处理任务的代码段描述符及选择子 GPCode Desc <GPCodeLen-1,GPCodeSeg,,ATCE,D32,> GPCode_Sel = GPCode-GDT ;其它中断或异常处理程序代码段(一致可读)描述符及选择子 ErrCode Desc <ErrCodeLen-1,ErrCodeSeg,,ATCCOR,D32,> ErrCode_Sel = ErrCode-GDT ;---------------------------------------------------------------------------- GDNum = ($-EFFGDT)/(SIZE Desc) ;需处理基地址的描述符个数 ;---------------------------------------------------------------------------- ;指向测试任务的任务门 TestTask Gate <,TestTSS_Sel,,ATTaskGate,> Test_Sel = TestTask-GDT ;---------------------------------------------------------------------------- GDTLen = $-GDT ;全局描述符表长度 GDTSeg ENDS ;全局描述符表段定义结束 ;---------------------------------------------------------------------------- IDTSeg SEGMENT PARA USE16 ;中断描述符表段(16位) IDT LABEL BYTE ;中断描述符表 REPT 13 Gate <ErrBegin,ErrCode_Sel,,AT386TGate,> ENDM Gate <,GPTSS_Sel,,ATTaskGate,> ;通用故障处理程序门描述符 REPT 242 Gate <ErrBegin,ErrCode_Sel,,AT386TGate,> ENDM ;---------------------------------------------------------------------------- IDTLen = $-IDT ;---------------------------------------------------------------------------- IDTSeg ENDS ;中断描述符表段定义结束 ;---------------------------------------------------------------------------- ;其它中断或异常处理程序的代码段(一致可读) ;---------------------------------------------------------------------------- ErrCodeSeg SEGMENT PARA USE32 ASSUME CS:ErrCodeSeg ;---------------------------------------------------------------------------- ErrMess DB 'Error!!!' ErrMessLen = $-ErrMess ;---------------------------------------------------------------------------- ErrBegin PROC FAR cld mov ax,ErrCode_Sel mov ds,ax lea esi,ErrMess mov ax,VideoBuf_Sel mov es,ax mov edi,1992 mov ecx,ErrMessLen mov ah,4eh Err1: lodsb stosw loop Err1 jmp $ ErrBegin ENDP ;---------------------------------------------------------------------------- ErrCodeLen = $ ErrCodeSeg ENDS ;---------------------------------------------------------------------------- GPTSSSeg SEGMENT PARA USE16 ;通用保护故障处理任务的TSS GPTaskSS LABEL BYTE DD 0 ;任务嵌套时的链接指针 DD 0 ;0级堆栈偏移 DW 0,0 ;0级堆栈选择子 DD 0 ;1级堆栈偏移 DW 0,0 ;1级堆栈选择子 DD 0 ;2级堆栈偏移 DW 0,0 ;2级堆栈选择子 DD 0 ;CR3 DW GPBegin,0 ;EIP DD 0 ;EFLAGS DD 0 ;EAX DD 0 ;ECX DD 0 ;EDX DD 0 ;EBX DD GPStackLen ;ESP DD 0 ;EBP DD 0 ;ESI DD 0 ;EDI DW VideoBuf_Sel,0 ;ES DW GPCode_Sel,0 ;CS DW GPStack_Sel,0 ;SS DW ToTestTSS_Sel,0 ;DS DW ToGPTSS_Sel,0 ;FS DW 0,0 ;GS DW 0,0 ;LDTR DW 0 ;调试陷阱标志 DW $+2 ;指向I/O许可位图的偏移 DB 0ffh ;I/O许可位图结束标志 GPTSSLen = $ GPTSSSeg ENDS ;---------------------------------------------------------------------------- GPStackSeg SEGMENT PARA USE32 ;通用保护故障处理任务堆栈段 GPStackLen = 512 DB GPStackLen DUP(0) GPStackSeg ENDS ;---------------------------------------------------------------------------- ;通用保护故障处理程序代码段 ;---------------------------------------------------------------------------- GPCodeSeg SEGMENT PARA USE32 ASSUME CS:GPCodeSeg ;---------------------------------------------------------------------------- GPBegin PROC FAR ;在屏幕左上角显示故障点 xor edi,edi mov ebx,OFFSET TestTaskSS mov edx,DWORD PTR [ebx].TRCS call EchoEDX mov ax,(17h SHL 8)+':' stosw mov edx,[ebx].TREIP call EchoEDX ;演示以便看清故障点 mov ecx,1234567h loop $ ;调整任务链接指针,中止故障任务 mov ebx,OFFSET GPTaskSS mov ax,DemoTSS_Sel mov fs:[ebx].TRLink,ax add esp,4 iretd jmp GPBegin GPBegin ENDP ;---------------------------------------------------------------------------- ;显示edx内容的子程序 ;---------------------------------------------------------------------------- EchoEDX PROC mov ah,17h mov ecx,8 EchoEDX1: rol edx,4 mov al,dl call HToASCII stosw loop EchoEDX1 ret EchoEDX ENDP ;---------------------------------------------------------------------------- ;把4位二进制数转换成对应的ASCII码 ;---------------------------------------------------------------------------- HToASCII PROC and al,0fh add al,90h daa adc al,40h daa ret HToASCII ENDP ;---------------------------------------------------------------------------- GPCodeLen = $ GPCodeSeg ENDS ;---------------------------------------------------------------------------- ;测试任务的TSS段 TestTSSSeg SEGMENT PARA USE16 TestTaskSS TSS <> ;TSS的固定格式部分 IOMap LABEL BYTE ;I/O许可位图 DB 8 DUP(0ffh) ;端口00h--3fh DB 11111011b ;端口40h--47h DB 3 DUP(0ffh) ;端口48h--5fh DB 11111101b ;端口60h--67h DB 0 ;端口68h--6fh DB 0ffh ;I/O许可位图结束标志 TestTSSLen = $ TestTSSSeg ENDS ;---------------------------------------------------------------------------- ;测试任务的堆栈段 TestStackSeg SEGMENT PARA USE32 TestStackLen = 1024 DB TestStackLen DUP(0) TestStackSeg ENDS ;---------------------------------------------------------------------------- ;测试任务的代码段 TestCodeSeg SEGMENT PARA USE32 ASSUME CS:TestCodeSeg ;---------------------------------------------------------------------------- Test3Begin PROC FAR cli ;I/O敏感指令 clts ;特权指令 iretd jmp Test3Begin Test3Begin ENDP ;---------------------------------------------------------------------------- TestBegin PROC FAR mov al,0b6h ;使扬声器发出一长声 out 43h,al mov al,2 out 42h,al mov al,34h out 42h,al in al,61h mov ah,al or al,3 out 61h,al mov ecx,1234567h loop $ mov al,ah out 61h,al iretd jmp TestBegin TestBegin ENDP ;---------------------------------------------------------------------------- TestCodeLen = $ TestCodeSeg ENDS ;---------------------------------------------------------------------------- ;演示任务TSS段 DemoTSSSeg SEGMENT PARA USE16 DemoTaskSS TSS <> DB 0ffh ;I/O许可位图结束字节 DemoTSSLen = $ DemoTSSSeg ENDS ;---------------------------------------------------------------------------- ;演示任务的堆栈段 DemoStackSeg SEGMENT PARA USE32 DemoStackLen = 1024 DB DemoStackLen DUP(0) DemoStackSeg ENDS ;---------------------------------------------------------------------------- ;演示任务的代码段 DemoCodeSeg SEGMENT PARA USE32 ASSUME CS:DemoCodeSeg ;---------------------------------------------------------------------------- DemoBegin PROC FAR mov ax,ToTestTSS_Sel mov ds,ax mov ebx,OFFSET TestTaskSS ;把测试任务1的入口点,堆栈指针和标志值(含IOPL)填入测试任务TSS mov WORD PTR [ebx].TRSS,Test1Stack_Sel mov DWORD PTR [ebx].TRESP,TestStackLen mov WORD PTR [ebx].TRCS,Test1Code_Sel mov DWORD PTR [ebx].TREIP,OFFSET TestBegin mov DWORD PTR [ebx].TREFLAG,IOPL1 ;通过任务门调用测试任务 CALL32 Test_Sel,0 ;把测试任务2的入口点,堆栈指针和标志值(含IOPL)填入测试任务TSS mov WORD PTR [ebx].TRSS,Test2Stack_Sel mov DWORD PTR [ebx].TRESP,TestStackLen mov WORD PTR [ebx].TRCS,Test2Code_Sel mov DWORD PTR [ebx].TREIP,OFFSET TestBegin mov DWORD PTR [ebx].TREFLAG,IOPL1 ;通过任务门调用测试任务 CALL32 Test_Sel,0 ;把测试任务TSS描述符内的属性置为"可用" mov ax,ToGDT_Sel mov fs,ax mov fs:TestTSS.Attributes,AT386TSS ;把测试任务3的入口点,堆栈指针和标志值(含IOPL)填入测试任务TSS mov WORD PTR [ebx].TRSS,Test3Stack_Sel mov DWORD PTR [ebx].TRESP,TestStackLen mov WORD PTR [ebx].TRCS,Test3Code_Sel mov DWORD PTR [ebx].TREIP,OFFSET Test3Begin mov DWORD PTR [ebx].TREFLAG,IOPL2 ;通过任务门调用测试任务 CALL32 Test_Sel,0 ;把测试任务TSS描述符内的属性置为"可用" mov ax,ToGDT_Sel mov fs,ax mov fs:TestTSS.Attributes,AT386TSS ;把测试任务4的入口点,堆栈指针和标志值(含IOPL)填入测试任务TSS mov WORD PTR [ebx].TRSS,Test3Stack_Sel mov DWORD PTR [ebx].TRESP,TestStackLen mov WORD PTR [ebx].TRCS,Test3Code_Sel mov DWORD PTR [ebx].TREIP,OFFSET Test3Begin mov DWORD PTR [ebx].TREFLAG,IOPL3 ;通过任务门调用测试任务 CALL32 Test_Sel,0 JUMP32 TempCode_Sel,<OFFSET ToDOS> DemoBegin ENDP ;---------------------------------------------------------------------------- DemoCodeLen = $ DemoCodeSeg ENDS ;---------------------------------------------------------------------------- TempCodeSeg SEGMENT PARA USE16 ;演示任务的临时代码段 ASSUME CS:TempCodeSeg ;---------------------------------------------------------------------------- Virtual PROC FAR ;置数据段寄存器为空 mov ax,0 mov ds,ax mov es,ax mov fs,ax mov gs,ax ;置堆栈指针 mov ax,DemoStack_Sel mov ss,ax mov esp,DemoStackLen ;置任务寄存器 mov ax,DemoTSS_Sel ltr ax ;转演示代码段 JUMP16 DemoCode_Sel,DemoBegin ToDOS: clts mov ax,Normal_Sel mov ds,ax mov es,ax mov fs,ax mov gs,ax mov ss,ax mov eax,cr0 and al,11111110b mov cr0,eax JUMP16 <SEG Real>,<OFFSET Real> Virtual ENDP ;---------------------------------------------------------------------------- TempCodeSeg ENDS ;============================================================================ RDataSeg SEGMENT PARA USE16 ;实方式数据段 VGDTR PDesc <GDTLen-1,> ;GDT伪描述符 VIDTR PDesc <IDTLen-1,> ;IDT伪描述符 NORVIDTR PDesc <3ffh,> ;用于保存原IDTR值 SPVar DW ? ;用于保存实方式下的SP SSVar DW ? ;用于保存实方式下的SS RDataSeg ENDS ;---------------------------------------------------------------------------- RCodeSeg SEGMENT PARA USE16 ;实方式代码段 ASSUME CS:RCodeSeg,DS:RDataSeg ;---------------------------------------------------------------------------- Start PROC mov ax,RDataSeg mov ds,ax cld call InitGDT ;初始化全局描述符表GDT call InitIDT ;初始化中断描述符表IDT lgdt QWORD PTR VGDTR ;装载GDTR mov SSVar,ss ;保存堆栈指针 mov SPVar,sp sidt QWORD PTR NORVIDTR ;保存IDTR cli ;关中断 lidt QWORD PTR VIDTR ;装载IDTR mov eax,cr0 or al,1 mov cr0,eax JUMP16 <TempCode_Sel>,<OFFSET Virtual> Real: mov ax,RDataSeg mov ds,ax lss sp,DWORD PTR SPVar ;又回到实方式 lidt QWORD PTR NORVIDTR sti mov ax,4c00h int 21h Start ENDP ;---------------------------------------------------------------------------- InitGDT PROC push ds mov ax,GDTSeg mov ds,ax mov cx,GDNum mov si,OFFSET EFFGDT InitG: mov ax,[si].BaseL movzx eax,ax shl eax,4 shld edx,eax,16 mov WORD PTR [si].BaseL,ax mov BYTE PTR [si].BaseM,dl mov BYTE PTR [si].BaseH,dh add si,SIZE Desc loop InitG pop ds mov bx,16 mov ax,GDTSeg mul bx mov WORD PTR VGDTR.Base,ax mov WORD PTR VGDTR.Base+2,dx ret InitGDT ENDP ;---------------------------------------------------------------------------- InitIDT PROC mov bx,16 mov ax,IDTSeg mul bx mov WORD PTR VIDTR.Base,ax mov WORD PTR VIDTR.Base+2,dx ret InitIDT ENDP ;---------------------------------------------------------------------------- RCodeSeg ENDS END Start
参考资料 | 书 名 | 出 版 社 | 作 者 |
《保护方式下的80386及其编程》 | 清华大学出版社 | 周明德主编 | |
《80X86汇编语言程序设计教程》 | 清华大学出版社 | 扬季文主编 |